November 2000


  Testing Buffer Overflows (cont'd)



Testing Socket-Based Applications

 

Testing Socket-Based Applications
When it comes to testing sockets, few languages have the ease and flexibility of Perl. That is not to say you need to be a Perl programmer to test sockets-based applications, but adding Perl to your toolbox is useful. I really like Perl because it has excellent socket support (with high-level classes for HTTP, SMTP, NNTP, HTML, XML, and more), great buffer manipulation, and the best regular expression parsing in the industry (helpful when searching for status codes and error condition).

The following sample client code will open a socket at port TCP\1777 on a server named 'foobar' and send 16,386 bytes of 'A's to that socket:

use IO::Socket;
my $server = 'ServerName';
my $port = 1777;
my $junk = 'A' x 16384;
if (($socks = IO::Socket::INET->new(Proto => "tcp", 
                                    PeerAddr => $server, 
                                    PeerPort => $port,
                                    TimeOut => 5))) {
    printf "Sending %d bytes\r", length $junk;
    $socks->send($junk);
}

If you want to send absolute garbage to the port, change the $junk line to read:

srand time;
my @chars = ('A' .. 'Z', 'a' .. 'z', 0 .. 9, qw( ! @ # $ % ^ & * - + = ));
my $junk = join ("", @chars[ map{rand @chars } (1 .. 16384)]);

If you are testing Web servers or applications residing on top of a Web server, Perl can mimic a browser, using the LWP::UserAgent class. The following example creates a very large HTTP POST request and then looks for an error back from the server. In this example, an error condition is either a non-200 HTTP code or body text containing the word 'Illegal Operation':

use HTTP::Request::Common qw(POST GET);
use HTTP::Headers;
use LWP::UserAgent;
my $ua = LWP::UserAgent->new();
$ua->agent("HackZilla/v42.42 Windows 2000"); // Set our own user-agent string!
my $url = "http://foobar/mytest.asp";
my $req = POST $url, [Name => 'A' x 128, Address => 'B' x 256000, Zip => 'C' x 128];
my $res = $ua->request($req);
my $err = $res->status_line;    // Get the error back from the server
$_ = $res->as_string;    // Get server body text, $_ used in regexp on next line
if (/Illegal Operation/ig || $err != 200) {
    print "Server returned error.\n";
}

Finally, you can use Perl to create binary blobs using the pack function to send to a port. Take a look at the following vulnerable C++ code. It creates a socket server on port 1777 and creates a data structure, MYBLOB, defined in Step 1:

MYBLOB blob;
ZeroMemory(&blob,sizeof blob);

AfxSocketInit(); int iSockPort = 1777;

CSocket sockServer; CSocket sockClient; sockServer.Create(iSockPort); cout << "Waiting for a connection on port " << iSockPort << endl; sockServer.Listen(); sockServer.Accept(sockClient); sockClient.Receive(&blob,sizeof blob);

// now copy the buffer char bTemp[MAX_BUFF]; CopyMemory(bTemp,blob.bData,blob.cSize);

The following Perl code will cause the C++ server to fail after the call to CopyMemory(), because the Perl code sets the cSize value greater than the largest size possible in the data structure (cSize is 250, while bData is fixed to 128 bytes), and CopyMemory() assumes the value in cSize is always less than or equal to MAX_BUFF bytes.

use IO::Socket;
my $MAX_BUFF = 128;
my $bData = 'A' x $MAX_BUFF;
my $cSize = 250;
my $iID = 0;
my $server = '127.0.0.1';
my $port = 1777;
if (($socks=IO::Socket::INET->new(Proto=>"tcp",PeerAddr=>$server,
    PeerPort => $port,
    TimeOut => 5))) {
    my $goo = pack "cia128",$cSize,$iID,$bData;
    printf "Sending junk to $port (%d bytes)", length $goo;
    $socks->send($goo);
}

Hopefully, your code is resilient to this kind of junk!

When using pack, 'c' means a char, 'i' is a signed integer, and 'a128' means 128 string characters. So the sample above creates a buffer of one character and one signed integer followed by 128 characters. That pack can also handle big and little endian values, floating point, Unicode, and ANSI/ASCII/EBCDIC strings, BER-encoded data, and more.

By the way, the remedy for the socket server code is to change the call to CopyMemory() to read like this:

CopyMemory(bTemp,blob.bData,min(MAX_BUFF,blob.cSize));

Previous: Page 1  Next: Testing RPC and DCOM-Based Applications

 
Resources
• "Smashing the Stack for Fun and Profit" by Aleph One.

• An excellent Perl for Windows is available from www.activestate.com.

• Michael Howard will answer your follow-up questions regarding buffer overruns. Just post them to the DevX bugs discussion group.

• For an end-to-end view of all the Win2000 security services, check out Michael Howard's book Designing Secure Web-Based Applications for Microsoft Windows 2000.


Sponsored Links


Advertising Info  |   Member Services  |   Contact Us  |   Help  |   Feedback  |   Site Map
Jupiterweb networks

internet.comearthweb.comDevx.comClickZ

Search Jupiterweb:

Jupitermedia Corporation has four divisions:
JupiterWeb, JupiterResearch, JupiterEvents, and JupiterImages

Copyright 2004 Jupitermedia Corporation All Rights Reserved.
Legal Notices, Licensing, Reprints, & Permissions, Privacy Policy.

Jupitermedia Corporate Info | Newsletters | Tech Jobs | E-mail Offers